﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DamageCalculator.SubForms;
using DamageCalculator.Classes;
using DamageCalculator.Properties;
using System.IO;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;

namespace DamageCalculator
{
    public delegate void AddEntryDelegate(Entry e);
    public delegate void VoidDelegate();


    public partial class Frm_Main : Form
    {
        List<Classes.GameSettings> GS;
        int ReadLinesCount;
        List<Classes.Character> Chars;
        DateTime LastTime;
        Encounter currentencounter;
        List<Encounter> EncounterRecords;
        WindowedModeGameOverlay Gover;
        GraphType GT;
        bool hasbeenautocopied = false;

        [DllImport("user32.dll")]
        static extern int SetScrollPos(IntPtr hWnd, int nBar,
                                       int nPos, bool bRedraw);
        [DllImport("user32.dll")]
        static extern int SendMessage(IntPtr hWnd, int wMsg,
                                       int wParam, int lParam);

        const int EM_LINESCROLL = 0x00B6;

        public enum GraphType
        {
            DPS,
            TotalDmg,
            DmgPie,
        }

        public Frm_Main()
        {
            InitializeComponent();
            GS = new List<GameSettings>();
            this.Chars = new List<Character>();
            this.LoadGames();
            ReadLinesCount = 0;
            this.PreloadLog();
            this.LastTime = DateTime.Now;
            this.currentencounter = null;
            this.EncounterRecords = new List<Encounter>();
            this.GT = GraphType.DPS;
            this.Gover = new WindowedModeGameOverlay(this.GT, (GameSettings)this.Stat_lbl_CurrentGame.Tag, this);
            this.SetupGraph();
            this.autoaddCharactersToWatchlistToolStripMenuItem.Checked = Properties.Settings.Default.AutoAdd;
        }

        private void AddEntrytoLog(Entry E)
        {
            if (this.LB_Entries.InvokeRequired)
            {
                AddEntryDelegate d = new AddEntryDelegate(AddEntrytoLog);
                this.Invoke(d, new object[] { E });
            }
            else
            {
                //listBox1.Items.Add("Some Text " + listBox1.Items.Count.ToString());

                ////The max number of items that the listbox can display at a time
                //int NumberOfItems = listBox1.ClientSize.Height / listBox1.ItemHeight;

                //if (listBox1.TopIndex == listBox1.Items.Count - NumberOfItems - 1)
                //{
                //    //The item at the top when you can just see the bottom item
                //    listBox1.TopIndex = listBox1.Items.Count - NumberOfItems + 1;
                //}
                this.LB_Entries.Items.Add(E.ToString());
                int numberofitems = this.LB_Entries.ClientSize.Height / this.LB_Entries.ItemHeight;

                this.LB_Entries.TopIndex = this.LB_Entries.Items.Count - numberofitems + 1;
            }
        }

        private void SetupGraph()
        {
            switch (this.GT)
            {
                case GraphType.DPS:
                    this.CHRT_DPS_HPS.Series.Clear();
                    this.CHRT_DPS_HPS.ChartAreas.Clear();
                    this.CHRT_DPS_HPS.Titles.Clear();
                    this.CHRT_DPS_HPS.Titles.Add("DPS Chart");
                    this.CHRT_DPS_HPS.Legends[0].Enabled = true;

                    System.Windows.Forms.DataVisualization.Charting.ChartArea C1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea("C1");
                    this.CHRT_DPS_HPS.ChartAreas.Add(C1);

                    System.Windows.Forms.DataVisualization.Charting.Series s1 = new System.Windows.Forms.DataVisualization.Charting.Series("DPS");
                    s1.Color = System.Drawing.Color.Red;
                    s1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Bar;
                    s1.ChartArea = this.CHRT_DPS_HPS.ChartAreas[0].Name;
                    s1.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
                    s1.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
                    s1.Name = "DPS";
                    s1["PointWidth"] = "1";
                    this.CHRT_DPS_HPS.Series.Add(s1);

                    System.Windows.Forms.DataVisualization.Charting.Series s2 = new System.Windows.Forms.DataVisualization.Charting.Series("HPS");
                    s2.Color = System.Drawing.Color.Blue;
                    s2.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Bar;
                    s2.ChartArea = this.CHRT_DPS_HPS.ChartAreas[0].Name;
                    s2.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
                    s2.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
                    s2.Name = "HPS";
                    s2["PointWidth"] = "1";
                    this.CHRT_DPS_HPS.Series.Add(s2);

                    break;

                case GraphType.TotalDmg:
                    this.CHRT_DPS_HPS.Series.Clear();
                    this.CHRT_DPS_HPS.ChartAreas.Clear();
                    this.CHRT_DPS_HPS.Titles.Clear();
                    this.CHRT_DPS_HPS.Titles.Add("Total Damage Chart");
                    this.CHRT_DPS_HPS.Legends[0].Enabled = true;;

                    System.Windows.Forms.DataVisualization.Charting.ChartArea C2 = new System.Windows.Forms.DataVisualization.Charting.ChartArea("C2");
                    this.CHRT_DPS_HPS.ChartAreas.Add(C2);

                    System.Windows.Forms.DataVisualization.Charting.Series s3 = new System.Windows.Forms.DataVisualization.Charting.Series("Damage");
                    s3.Color = System.Drawing.Color.Red;
                    s3.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Bar;
                    s3.ChartArea = this.CHRT_DPS_HPS.ChartAreas[0].Name;
                    s3.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
                    s3.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
                    s3.Name = "Damage";
                    s3["PointWidth"] = "1";
                    this.CHRT_DPS_HPS.Series.Add(s3);

                    System.Windows.Forms.DataVisualization.Charting.Series s4 = new System.Windows.Forms.DataVisualization.Charting.Series("Healing");
                    s4.Color = System.Drawing.Color.Blue;
                    s4.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Bar;
                    s4.ChartArea = this.CHRT_DPS_HPS.ChartAreas[0].Name;
                    s4.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
                    s4.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
                    s4.Name = "Healing";
                    s4["PointWidth"] = "1";
                    this.CHRT_DPS_HPS.Series.Add(s4);

                    break;

                case GraphType.DmgPie:
                    this.CHRT_DPS_HPS.Series.Clear();
                    this.CHRT_DPS_HPS.ChartAreas.Clear();
                    this.CHRT_DPS_HPS.Titles.Clear();
                    this.CHRT_DPS_HPS.Legends[0].Enabled = false;

                    //Add Chart Areas
                    System.Windows.Forms.DataVisualization.Charting.ChartArea cDmg = new System.Windows.Forms.DataVisualization.Charting.ChartArea("Damage");
                    cDmg.Position.Auto = false;
                    cDmg.Position.X = 0;
                    cDmg.Position.Y = 0;
                    cDmg.Position.Height = 100;
                    cDmg.Position.Width = 49;
                    this.CHRT_DPS_HPS.ChartAreas.Add(cDmg);

                    System.Windows.Forms.DataVisualization.Charting.ChartArea cHeal = new System.Windows.Forms.DataVisualization.Charting.ChartArea("Healing");
                    cHeal.Position.Auto = false;
                    cHeal.Position.X = 50;
                    cHeal.Position.Y = 0;
                    cHeal.Position.Height = 100;
                    cHeal.Position.Width = 49;
                    this.CHRT_DPS_HPS.ChartAreas.Add(cHeal);

                    //Add Chart Titles
                    System.Windows.Forms.DataVisualization.Charting.Title tDmg = new System.Windows.Forms.DataVisualization.Charting.Title("Damage", System.Windows.Forms.DataVisualization.Charting.Docking.Top);
                    tDmg.DockedToChartArea = "Damage";
                    this.CHRT_DPS_HPS.Titles.Add(tDmg);

                    System.Windows.Forms.DataVisualization.Charting.Title tHeal = new System.Windows.Forms.DataVisualization.Charting.Title("Healing", System.Windows.Forms.DataVisualization.Charting.Docking.Top);
                    tHeal.DockedToChartArea = "Healing";
                    this.CHRT_DPS_HPS.Titles.Add(tHeal);

                    //Add Series
                    System.Windows.Forms.DataVisualization.Charting.Series sDmg = new System.Windows.Forms.DataVisualization.Charting.Series("Damage");
                    sDmg.ChartArea = "Damage";
                    sDmg.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Pie;
                    sDmg.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
                    sDmg.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
                    this.CHRT_DPS_HPS.Series.Add(sDmg);

                    System.Windows.Forms.DataVisualization.Charting.Series sHeal = new System.Windows.Forms.DataVisualization.Charting.Series("Healing");
                    sHeal.ChartArea = "Healing";
                    sHeal.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Pie;
                    sHeal.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
                    sHeal.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
                    this.CHRT_DPS_HPS.Series.Add(sHeal);

                    break;
            }
        }

        private void PreloadLog()
        {
            this.LastTime = DateTime.Now;
            this.currentencounter = null;
            this.EncounterRecords = new List<Encounter>();
            this.Chars = new List<Character>();
            this.Lv_Stats.Items.Clear();
            this.ReadLinesCount = 0;
            try
            {
                Classes.GameSettings GS = this.Stat_lbl_CurrentGame.Tag as Classes.GameSettings;
                StreamReader SR = new StreamReader(new FileStream(GS.LogFilePath, FileMode.Open, FileAccess.Read, System.IO.FileShare.ReadWrite));

                while (!SR.EndOfStream)
                {
                    SR.ReadLine();
                    this.ReadLinesCount++;
                }

                SR.Close();
            }
            catch
            {
                MessageBox.Show("There is an issue with this game settings file. Please ensure that your character name and the log file path are set correctly.");
            }
        }

        private void LoadGames()
        {
            this.GS.Clear();
            this.currentGameToolStripMenuItem.DropDownItems.Clear();

            this.GS = Classes.StaticFunctions.GetGamesSettingsList();

            foreach (Classes.GameSettings G in this.GS)
            {
                ToolStripMenuItem temp = new ToolStripMenuItem(G.GameName);
                temp.Click += new EventHandler(temp_Click);
                temp.CheckOnClick = true;
                if ((Settings.Default.LastUsedGame == "" && G == this.GS[0]) || (G.GameName == Settings.Default.LastUsedGame))
                {
                    temp.Checked = true;

                    if (Settings.Default.LastUsedGame == "")
                    {
                        Settings.Default.LastUsedGame = G.GameName;
                        Settings.Default.Save();
                    }

                    this.Stat_lbl_CurrentGame.Text = G.GameName;
                    this.Stat_lbl_CurrentGame.Tag = G;
                }

                this.currentGameToolStripMenuItem.DropDownItems.Add(temp);
            }
        }

        public void EncounterSwitch(object sender, EventArgs e)
        {
            ToolStripMenuItem T = sender as ToolStripMenuItem;

            foreach (ToolStripMenuItem t in this.viewToolStripMenuItem.DropDownItems)
            {
                if (t.Text != T.Text)
                    t.Checked = false;
            }
        }

        private void SwitchGraph(object sender, EventArgs e)
        {
            ToolStripMenuItem T = sender as ToolStripMenuItem;

            switch (T.Text)
            {
                case "DPS/HPS":
                    this.GT = GraphType.DPS;
                    break;

                case "Damage Plot":
                    this.GT = GraphType.TotalDmg;
                    break;

                case "Damage Pie":
                    this.GT = GraphType.DmgPie;
                    break;
            }

            this.Gover.SetGraph(this.GT);

            this.SetupGraph();
        }

        public void OverlaySwitchedGraph(String OverlayOptionText)
        {
            ToolStripMenuItem temp = new ToolStripMenuItem(OverlayOptionText);

            foreach (ToolStripMenuItem T in this.chartsToolStripMenuItem.DropDownItems)
            {
                if (T.Text == OverlayOptionText)
                    T.Checked = true;
                else
                    T.Checked = false;
            }

            this.SwitchGraph(temp, null);
        }

        void temp_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem temp = sender as ToolStripMenuItem;
            this.timer.Enabled = false;
            this.Stat_lbl_TimeElapsedSinceStart.Text = "Watch Time: 00:00:00";
            foreach (ToolStripMenuItem TS in this.currentGameToolStripMenuItem.DropDownItems)
            {
                if (TS != temp)
                    TS.Checked = false;
            }

            foreach (GameSettings G in this.GS)
            {
                if (G.GameName == temp.Text)
                {
                    Settings.Default.LastUsedGame = G.GameName;
                    Settings.Default.Save();

                    this.Stat_lbl_CurrentGame.Text = G.GameName;
                    this.Stat_lbl_CurrentGame.Tag = G;
                    break;
                }
            }

            this.PreloadLog();
        }

        private void editGameSettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GamesSettings GS = new GamesSettings();
            GS.SettingsUpdateRequired += new GamesSettings.NothingPassedDelegate(GS_SettingsUpdateRequired);
            GS.Show();
        }

        private void GS_SettingsUpdateRequired()
        {
            this.LoadGames();
        }

        private void startReadingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.timer.Enabled = true;
            this.StripLbl_Status.Text = "Running";
        }

        private String[] ReadNewLines()
        {
            //Get Game Settings to find out filepath Info
            Classes.GameSettings G = this.Stat_lbl_CurrentGame.Tag as Classes.GameSettings;

            using (StreamReader SR = new StreamReader(new FileStream(G.LogFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
            {
                int readlinescountsnapshot = this.ReadLinesCount;

                for (int i = 0; i < readlinescountsnapshot; i++)
                    SR.ReadLine();

                List<String> NewLines = new List<string>();

                while (!SR.EndOfStream)
                {
                    NewLines.Add(SR.ReadLine());
                    this.ReadLinesCount++;
                }
                SR.Close();
                return NewLines.ToArray();
            }
        }

        private Entry ParseLine(String Line, String ParseTerm, ParsableLogEntry.EventTypes EType)
        {
            Classes.GameSettings G = this.Stat_lbl_CurrentGame.Tag as Classes.GameSettings;
            String L = Line;
            List<String> Tokens = new List<string>();

            Char[] LineArray = ParseTerm.ToArray<char>();

            //find and log all special tokens in the string
            for (int i = 0; i < LineArray.Length; i++)
            {
                if (LineArray[i] == '[' && i == 0)
                {
                    String temp = "";
                    i++;
                    while (LineArray[i] != ']')
                    {
                        temp += LineArray[i].ToString();
                        i++;
                    }
                    i++;
                    Tokens.Add(temp.ToLower());
                }

                else if (LineArray[i] == '[' && LineArray[i - 1] != '\\')
                {
                    String temp = "";
                    i++;
                    while (LineArray[i] != ']')
                    {
                        temp += LineArray[i].ToString();
                        i++;
                    }
                    Tokens.Add(temp.ToLower());
                }
            }

            //replace tokens with their proper regex statements
            foreach (String Token in Tokens)
            {
                String T = Token.ToLower();
                String exceptString = "";
                if (T.Contains("!"))
                {
                    String[] temp = Regex.Split(T, "!");

                    T = temp[0];
                    exceptString = temp[1];
                    //(.*(?<!really))
                }
                switch (T)
                {
                    case "garbage":
                        if (exceptString == "")
                            ParseTerm = Regex.Replace(ParseTerm, @"\[garbage\]", @"(.+)", RegexOptions.IgnoreCase);
                        else
                            ParseTerm = Regex.Replace(ParseTerm, @"\[garbage!" + exceptString + @"\]", @"(.+(?<!" + exceptString + "))", RegexOptions.IgnoreCase);
                        break;

                    case "giving":
                    case "receiving":
                    case "damage type":
                    case "skill":
                        if(exceptString == "")
                            ParseTerm = Regex.Replace(ParseTerm, @"\[" + T + @"\]", @"(.+)", RegexOptions.IgnoreCase);
                        else
                            ParseTerm = Regex.Replace(ParseTerm, @"\[" + T + "!" + exceptString + @"\]", @"(.+(?<!" + exceptString + "))", RegexOptions.IgnoreCase);
                        break;

                    case "damage":
                        if (exceptString == "")
                            ParseTerm = Regex.Replace(ParseTerm, @"\[damage\]", @"(\d+\.{0,1}\d*)", RegexOptions.IgnoreCase);
                        else
                            throw new Exception("Numberical tags are not allowed to use the ! token");
                        break;

                    case "time":
                        if (exceptString == "")
                        {
                            switch (G.TimeFormat)
                            {
                                case GameSettings.TimeStampFormat.DateTimeString:
                                    String tempstampString = Regex.Replace(G.DateTimeStringFormat, @"[MmDYhs]", @"\d");
                                    ParseTerm = Regex.Replace(ParseTerm, @"\[time\]", "(" + tempstampString + ")", RegexOptions.IgnoreCase);
                                    break;

                                default:
                                    ParseTerm = Regex.Replace(ParseTerm, @"\[time\]", @"(\d+)", RegexOptions.IgnoreCase);
                                    break;
                            }
                        }
                        else
                            throw new Exception("Numberical tags are not allowed to use the ! token");
                        break;
                }
            }

            // build the final regex statement
            String endregex = "";
            for (int i = 1; i <= Tokens.Count; i++)
            {
                if (i > 1)
                    endregex += "\t";

                endregex += "$" + i;
            }
            ParseTerm = "^" + ParseTerm + "$";
            //run the final regex statement
            if (!Regex.IsMatch(L.Trim(), ParseTerm))
                return null;
            L = Regex.Replace(L.Trim(), ParseTerm, endregex);

            String[] splitstring = Regex.Split(L, "\t"); //split the entries into an array

            //build entry --> public Entry(int pTimeStamp, double pAmmount, String pSkill, String pOtherChar, String pActiveChar, ParsableLogEntry.EventTypes pEventType)

            int TimeIndx = Tokens.IndexOf("time");
            long Temptime = 0;
            if(TimeIndx >=0)
            {
                if (G.TimeFormat == GameSettings.TimeStampFormat.DateTimeString)
                {
                    DateTime TempDate = DateTime.Parse(splitstring[TimeIndx]);
                    double timepassed = (TempDate - new DateTime()).TotalSeconds;
                    Temptime = Convert.ToInt64(timepassed);
                }

                else
                    Temptime = long.Parse(splitstring[TimeIndx]);
            }

            int ammountindex = Tokens.IndexOf("damage");
            double ammout = 0;
            if(ammountindex >= 0)
                ammout = double.Parse(splitstring[ammountindex]);

            int Skillindex = Tokens.IndexOf("skill");
            String tempskill = "";

            if(Skillindex >= 0)
                tempskill = splitstring[Skillindex];


            int OthercharIndex = -1;
            int ActiveCharIndex = -1;
            if (EType.ToString().ToLower().Contains("get"))
            {
                OthercharIndex = Tokens.IndexOf("giving");
                ActiveCharIndex = Tokens.IndexOf("receiving");
            }
            else
            {
                OthercharIndex = Tokens.IndexOf("receiving");
                ActiveCharIndex = Tokens.IndexOf("giving");
            }

            String tempOtherChar = "";
            if(OthercharIndex >= 0)
                tempOtherChar = splitstring[OthercharIndex];

            String tempActiveChar = splitstring[ActiveCharIndex];

            if (tempOtherChar.ToLower() == "you" || tempOtherChar.ToLower() == "your" || tempOtherChar.ToLower() == "my" || tempOtherChar.ToLower() == "me")
                tempOtherChar = G.PlayerName;

            else if (tempActiveChar.ToLower() == "you" || tempActiveChar.ToLower() == "your" || tempActiveChar.ToLower() == "my" || tempActiveChar.ToLower() == "me")
                tempActiveChar = G.PlayerName;

            int DmgTypeIndex = Tokens.IndexOf("damage type");
            String tempDmgType = "";
            if (DmgTypeIndex >= 0)
                tempDmgType = splitstring[DmgTypeIndex];

            //return new entry
            return new Entry(Temptime, ammout, tempskill, tempOtherChar, tempActiveChar, tempDmgType, EType);
        }

        private void Bg_RunParsing_DoWork(object sender, DoWorkEventArgs e)
        {
            GameSettings G = this.Stat_lbl_CurrentGame.Tag as GameSettings;
            String[] LinesToParse = this.ReadNewLines();
            bool ranlines = false;
            if (this.autoaddCharactersToWatchlistToolStripMenuItem.Checked && this.discoverableModeToolStripMenuItem.Checked)
            {
                foreach (Character C in this.Chars)
                {
                    if(!C.isPet)
                        C.WatchChar = true;
                }
            }
            else if (!this.discoverableModeToolStripMenuItem.Checked)
            {
                List<Character> tempC = null;

                tempC = this.Chars.FindAll(
                    delegate(Character c)
                    {
                        return !(c.WatchChar || c.isPet);
                    }
                );

                if (tempC != null)
                {
                    foreach (Character c in tempC)
                        this.Chars.Remove(c);
                }
            }

            foreach (String L in LinesToParse)
            {
                foreach (ParsableLogEntry P in G.LogEntries)
                {
                    Entry temp = this.ParseLine(L, P.FormatString, P.Event);
                    Character tempChar2 = null;

                    if (temp != null)
                    {
                        tempChar2 = Chars.Find(
                                delegate(Character C)
                                {
                                    return (C.Name == temp.ActiveChar);
                                }
                                );
                    }

                    if (temp != null &&(tempChar2 != null || this.discoverableModeToolStripMenuItem.Checked))
                    {
                        ranlines = true;
                        this.LastTime = DateTime.Now;
                        if (this.currentencounter == null || !currentencounter.isOpen)
                        {
                            this.hasbeenautocopied = false;
                            currentencounter = new Encounter(StaticFunctions.GenerateEncounterID(), DateTime.Now);
                            this.EncounterRecords.Add(currentencounter);
                            this.Stat_Lbl_Current_Encounter.Text = "Current Encounter: " + currentencounter.EncounterID;
                            foreach(Character C in this.Chars)
                                C.Encounters.Add(new Encounter(currentencounter.EncounterID, currentencounter.StartTime));
                        }

                        Character tempChar = null;

                        tempChar = Chars.Find(
                            delegate(Character C)
                            {
                                return (C.Name == temp.ActiveChar);
                            }
                            );

                        if (tempChar != null)
                        {
                            if (tempChar.Encounters[tempChar.Encounters.Count - 1].EncounterID == currentencounter.EncounterID)
                            {
                                tempChar.Encounters[tempChar.Encounters.Count - 1].Entries.Add(temp);
                                this.AddEntrytoLog(temp);
                            }

                            else
                            {
                                long tempid = tempChar.Encounters[tempChar.Encounters.Count - 1].EncounterID;

                                DateTime tempEnd = this.EncounterRecords.Find(
                                    delegate(Encounter E)
                                    {
                                        return E.EncounterID == tempid;
                                    }
                                ).EndTime;

                                tempChar.Encounters[tempChar.Encounters.Count - 1].isOpen = false;
                                tempChar.Encounters[tempChar.Encounters.Count - 1].EndTime = tempEnd;

                                tempChar.Encounters.Add(new Encounter(currentencounter.EncounterID, currentencounter.StartTime));
                                tempChar.Encounters[tempChar.Encounters.Count - 1].Entries.Add(temp);
                                this.AddEntrytoLog(temp);
                            }
                        }
                        else // create new character and add the encounter and event
                        {
                           this.Chars.Add(new Character(temp.ActiveChar, currentencounter));

                           Character tempChar3 = Chars.Find(
                           delegate(Character C)
                           {
                               return ((C.Name == temp.ActiveChar && temp.EventType.ToString().ToLower().Contains("give")) || (C.Name == temp.OtherChar));
                           }
                           );
                           try
                           {
                               tempChar3.Encounters[tempChar3.Encounters.Count - 1].Entries.Add(temp);
                               if (this.autoaddCharactersToWatchlistToolStripMenuItem.Checked)
                                   tempChar3.WatchChar = true;
                               this.AddEntrytoLog(temp);
                           }
                           catch { }
                        }

                    }
                }
            }

            try
            {
                if ((DateTime.Now - this.LastTime).TotalSeconds >= Settings.Default.TimeBetweenEncounters && ranlines == false && this.currentencounter.isOpen)
                {
                    try
                    {
                        this.currentencounter.isOpen = false;
                        this.currentencounter.EndTime = DateTime.Now;

                        foreach (Character C in this.Chars)
                        {
                            C.Encounters[C.Encounters.Count - 1].isOpen = false;
                            DateTime temptime = C.Encounters[C.Encounters.Count - 1].StartTime;
                            try
                            {
                                double value = Math.Abs(Convert.ToDouble(C.Encounters[C.Encounters.Count - 1].Entries[0].TimeStamp - C.Encounters[C.Encounters.Count - 1].Entries[C.Encounters[C.Encounters.Count - 1].Entries.Count - 1].TimeStamp));
                                if(value > 0)
                                    temptime = temptime.AddSeconds(value);
                                else
                                    temptime = temptime.AddSeconds(1);
                            }
                            catch { temptime = this.currentencounter.EndTime; }
                            C.Encounters[C.Encounters.Count - 1].EndTime = temptime;
                        }

                    }
                    catch { }
                }
            }
            catch { }

            foreach (Character C in this.Chars)
            {
                if (this.currentEncounterToolStripMenuItem.Checked)
                {
                    try
                    {
                        C.Recalculate(this.currentencounter.EncounterID);
                    }
                    catch { }
                }
                else if (this.sessionTotalsToolStripMenuItem.Checked)
                    C.Recalculate();
            }
            if (this.currentencounter != null)
            {
                if (!this.currentencounter.isOpen && !this.hasbeenautocopied && Properties.Settings.Default.AutoCopyResults)
                {
                    this.hasbeenautocopied = true;
                    this.CopytoClipboard();
                }
            }
        }

        private void Bg_RunParsing_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            List<Character> temp = this.Chars.FindAll(
                delegate(Character C)
                {
                    return C.WatchChar;
                }
            );

            this.Lv_Stats.SuspendLayout();
            this.CHRT_DPS_HPS.SuspendLayout();
            if (this.GT == GraphType.DPS)
            {
                this.CHRT_DPS_HPS.Series["DPS"].Points.Clear();
                this.CHRT_DPS_HPS.Series["HPS"].Points.Clear();
            }
            else if (this.GT == GraphType.TotalDmg)
            {
                this.CHRT_DPS_HPS.Series["Damage"].Points.Clear();
                this.CHRT_DPS_HPS.Series["Healing"].Points.Clear();
            }
            else if (this.GT == GraphType.DmgPie)
            {
                this.CHRT_DPS_HPS.Series["Damage"].Points.Clear();
                this.CHRT_DPS_HPS.Series["Healing"].Points.Clear();
            }
            List<Character> OverlayUpdate = new List<Character>();

            for (int i = 0; i < this.Lv_Stats.Items.Count; i++)
            {
                Character C = this.Lv_Stats.Items[i].Tag as Character;
                StaticFunctions.LVICopy(C.GenerateListViewItem(), this.Lv_Stats.Items[i]);
                OverlayUpdate.Add(C);

                if (this.GT == GraphType.DPS)
                {
                    if (!Double.IsInfinity(Double.Parse(this.Lv_Stats.Items[i].SubItems[2].Text)))
                    {
                        System.Windows.Forms.DataVisualization.Charting.DataPoint dpstemp = new System.Windows.Forms.DataVisualization.Charting.DataPoint(this.CHRT_DPS_HPS.Series["DPS"]);
                        dpstemp.SetValueXY(C.Name, new object[] { Double.Parse(this.Lv_Stats.Items[i].SubItems[2].Text) });
                        this.CHRT_DPS_HPS.Series["DPS"].Points.Add(dpstemp);
                    }

                    if (!Double.IsInfinity(Double.Parse(this.Lv_Stats.Items[i].SubItems[7].Text)))
                    {
                        System.Windows.Forms.DataVisualization.Charting.DataPoint hpstemp = new System.Windows.Forms.DataVisualization.Charting.DataPoint(this.CHRT_DPS_HPS.Series["HPS"]);
                        hpstemp.SetValueXY(C.Name, new object[] { Double.Parse(this.Lv_Stats.Items[i].SubItems[7].Text) });

                        this.CHRT_DPS_HPS.Series["HPS"].Points.Add(hpstemp);
                    }
                }

                else if (this.GT == GraphType.TotalDmg)
                {
                    if (!Double.IsInfinity(Double.Parse(this.Lv_Stats.Items[i].SubItems[1].Text)))
                    {
                        System.Windows.Forms.DataVisualization.Charting.DataPoint dpstemp = new System.Windows.Forms.DataVisualization.Charting.DataPoint(this.CHRT_DPS_HPS.Series["Damage"]);
                        dpstemp.SetValueXY(C.Name, new object[] { Double.Parse(this.Lv_Stats.Items[i].SubItems[1].Text) });
                        this.CHRT_DPS_HPS.Series["Damage"].Points.Add(dpstemp);
                    }

                    if (!Double.IsInfinity(Double.Parse(this.Lv_Stats.Items[i].SubItems[6].Text)))
                    {
                        System.Windows.Forms.DataVisualization.Charting.DataPoint hpstemp = new System.Windows.Forms.DataVisualization.Charting.DataPoint(this.CHRT_DPS_HPS.Series["Healing"]);
                        hpstemp.SetValueXY(C.Name, new object[] { Double.Parse(this.Lv_Stats.Items[i].SubItems[6].Text) });

                        this.CHRT_DPS_HPS.Series["Healing"].Points.Add(hpstemp);
                    }
                }
                else if (this.GT == GraphType.DmgPie)
                {
                    if (!Double.IsInfinity(Double.Parse(this.Lv_Stats.Items[i].SubItems[1].Text)))
                    {
                        System.Windows.Forms.DataVisualization.Charting.DataPoint dpstemp = new System.Windows.Forms.DataVisualization.Charting.DataPoint(this.CHRT_DPS_HPS.Series["Damage"]);
                        dpstemp.SetValueXY(C.Name, new object[] { Double.Parse(this.Lv_Stats.Items[i].SubItems[1].Text) });
                        this.CHRT_DPS_HPS.Series["Damage"].Points.Add(dpstemp);
                    }

                    if (!Double.IsInfinity(Double.Parse(this.Lv_Stats.Items[i].SubItems[6].Text)))
                    {
                        System.Windows.Forms.DataVisualization.Charting.DataPoint hpstemp = new System.Windows.Forms.DataVisualization.Charting.DataPoint(this.CHRT_DPS_HPS.Series["Healing"]);
                        hpstemp.SetValueXY(C.Name, new object[] { Double.Parse(this.Lv_Stats.Items[i].SubItems[6].Text) });

                        this.CHRT_DPS_HPS.Series["Healing"].Points.Add(hpstemp);
                    }
                }
            }

            double totalDps = 0;

            foreach (Character C in this.Chars)
            {
                bool alreadyadded = false;
                foreach (ListViewItem LVI in this.Lv_Stats.Items)
                {
                    Character tempC = LVI.Tag as Character;
                    if (tempC == C)
                    {
                        if (!Double.IsInfinity(Double.Parse(LVI.SubItems[2].Text)))
                            totalDps += Double.Parse(LVI.SubItems[2].Text);
                        alreadyadded = true;
                        break;
                    }
                }

                if (!alreadyadded && C.WatchChar)
                {
                    ListViewItem LVITemp = C.GenerateListViewItem();
                    if (!Double.IsInfinity(Double.Parse(LVITemp.SubItems[2].Text)))
                        totalDps += Double.Parse(LVITemp.SubItems[2].Text);

                    this.Lv_Stats.Items.Add(LVITemp);
                    OverlayUpdate.Add(C);

                    if (this.GT == GraphType.DPS)
                    {
                        if (!Double.IsInfinity(Double.Parse(this.Lv_Stats.Items[this.Lv_Stats.Items.Count - 1].SubItems[2].Text)))
                        {
                            System.Windows.Forms.DataVisualization.Charting.DataPoint dpstemp = new System.Windows.Forms.DataVisualization.Charting.DataPoint(this.CHRT_DPS_HPS.Series["DPS"]);
                            dpstemp.SetValueXY(C.Name, new object[] { Double.Parse(this.Lv_Stats.Items[this.Lv_Stats.Items.Count - 1].SubItems[2].Text) });
                            this.CHRT_DPS_HPS.Series["DPS"].Points.Add(dpstemp);
                        }

                        if (!Double.IsInfinity(Double.Parse(this.Lv_Stats.Items[this.Lv_Stats.Items.Count - 1].SubItems[7].Text)))
                        {
                            System.Windows.Forms.DataVisualization.Charting.DataPoint hpstemp = new System.Windows.Forms.DataVisualization.Charting.DataPoint(this.CHRT_DPS_HPS.Series["HPS"]);
                            hpstemp.SetValueXY(C.Name, new object[] { Double.Parse(this.Lv_Stats.Items[this.Lv_Stats.Items.Count - 1].SubItems[7].Text) });

                            this.CHRT_DPS_HPS.Series["HPS"].Points.Add(hpstemp);
                        }
                    }

                    else if (this.GT == GraphType.TotalDmg)
                    {
                        if (!Double.IsInfinity(Double.Parse(this.Lv_Stats.Items[this.Lv_Stats.Items.Count - 1].SubItems[1].Text)))
                        {
                            System.Windows.Forms.DataVisualization.Charting.DataPoint dpstemp = new System.Windows.Forms.DataVisualization.Charting.DataPoint(this.CHRT_DPS_HPS.Series["Damage"]);
                            dpstemp.SetValueXY(C.Name, new object[] { Double.Parse(this.Lv_Stats.Items[this.Lv_Stats.Items.Count - 1].SubItems[1].Text) });
                            this.CHRT_DPS_HPS.Series["Damage"].Points.Add(dpstemp);
                        }

                        if (!Double.IsInfinity(Double.Parse(this.Lv_Stats.Items[this.Lv_Stats.Items.Count - 1].SubItems[6].Text)))
                        {
                            System.Windows.Forms.DataVisualization.Charting.DataPoint hpstemp = new System.Windows.Forms.DataVisualization.Charting.DataPoint(this.CHRT_DPS_HPS.Series["Healing"]);
                            hpstemp.SetValueXY(C.Name, new object[] { Double.Parse(this.Lv_Stats.Items[this.Lv_Stats.Items.Count - 1].SubItems[6].Text) });

                            this.CHRT_DPS_HPS.Series["Healing"].Points.Add(hpstemp);
                        }
                    }
                }
            }
            try
            {
                this.Lv_Stats.Sort();
            }
            catch { }
            this.Lv_Stats.ResumeLayout();
            this.CHRT_DPS_HPS.ResumeLayout();
            if (this.Gover.Visible)
                this.Gover.updateWindow(OverlayUpdate);

            this.Stat_Lbl_TotalDps.Text = "Total DPS: " + totalDps.ToString("0.00");
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            if(!this.Bg_RunParsing.IsBusy)
                this.Bg_RunParsing.RunWorkerAsync();

            String[] temp = Regex.Split(this.Stat_lbl_TimeElapsedSinceStart.Text, " ");
            TimeSpan tempspan = TimeSpan.Parse(temp[2]);
            tempspan = tempspan.Add(new TimeSpan(0, 0, 1));
            this.Stat_lbl_TimeElapsedSinceStart.Text = temp[0] + " " + temp[1] + " " + tempspan.Hours.ToString("00") + ":" + tempspan.Minutes.ToString("00") + ":" + tempspan.Seconds.ToString("00");
        }

        private void Lv_Stats_MouseDown(object sender, MouseEventArgs e)
        {
            //check if the button pressed was right click
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                //get listviewitem associated with region

                ListViewItem L = this.Lv_Stats.GetItemAt(e.X, e.Y);

                if (L == null)
                {
                    this.removeCharacterToolStripMenuItem.Enabled = false;
                    this.addPetToolStripMenuItem.Enabled = false;
                    this.removePetToolStripMenuItem.Enabled = false;
                }
                else
                {
                    this.removeCharacterToolStripMenuItem.Enabled = true;
                    this.removeCharacterToolStripMenuItem.Tag = L;
                    this.addPetToolStripMenuItem.Enabled = true;
                    this.addPetToolStripMenuItem.Tag = L;
                    this.removePetToolStripMenuItem.Enabled = true;
                    this.removePetToolStripMenuItem.Tag = L;
                }

                this.Ctxt_Summary.Show(this.Lv_Stats, new Point(e.X, e.Y));
            }
            else if (e.Button == System.Windows.Forms.MouseButtons.Left && e.Clicks == 2)
            {
                ListViewItem L = this.Lv_Stats.GetItemAt(e.X, e.Y);
                if (L != null)
                {
                    CharacterView CV = new CharacterView(((Character)L.Tag));
                    CV.ShowDialog();
                }
            }
            
        }

        private void addCharacterToWatchListToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddCharacterDialog ACD = new AddCharacterDialog(this.Chars);

            DialogResult D = ACD.ShowDialog();

            if (D == System.Windows.Forms.DialogResult.OK)
            {
                if (ACD.ReturnsCharacter)
                    ACD.SelectedCharacter.WatchChar = true;
                else
                {
                    Character temp = new Character(ACD.SelectedCharacterString);
                    temp.WatchChar = true;
                    this.Chars.Add(temp);
                }
            }
        }

        public List<Character> CharsList
        {
            get { return this.Chars; }
        }

        public void AddChar(AddCharacterDialog ACD)
        {
            if (ACD.ReturnsCharacter)
                ACD.SelectedCharacter.WatchChar = true;
            else
            {
                Character temp = new Character(ACD.SelectedCharacterString);
                temp.WatchChar = true;
                this.Chars.Add(temp);
            }
        }

        private void Frm_Main_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                GameSettings G = this.Stat_lbl_CurrentGame.Tag as GameSettings;

                using (StreamWriter SW = new StreamWriter(new FileStream(G.LogFilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)))
                {
                    //Do Nothing
                    SW.Close();
                }
            }
            catch { }
        }

        public void CopytoClipboard()
        {
            if (this.Lv_Stats.InvokeRequired)
            {
                //AddEntryDelegate d = new AddEntryDelegate(AddEntrytoLog);
                //this.Invoke(d, new object[] { E });

                VoidDelegate d = new VoidDelegate(CopytoClipboard);
                this.Invoke(d, null);
            }
            else
            {
                Clipboard.Clear();

                foreach (ListViewItem LVI in this.Lv_Stats.Items)
                {
                    Character C = LVI.Tag as Character;
                    Clipboard.SetText(Clipboard.GetText() + " | " + C.ToString());
                }
            }
        }

        private void Frm_Main_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyCode == Keys.C)
            {
                this.CopytoClipboard();
            }
        }

        private void openGameOverlayToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem t = sender as ToolStripMenuItem;
            if (t.Text == "Open Game Overlay")
            {
                t.Text = "Close Game Overlay";
                this.Gover = new WindowedModeGameOverlay(this.GT, (GameSettings)this.Stat_lbl_CurrentGame.Tag, this);
                this.Gover.TopMost = true;
                int Xpos = Screen.PrimaryScreen.WorkingArea.Width;
                this.Gover.Show();
                this.Gover.Location = new Point(Properties.Settings.Default.OverlayLastXPos, Properties.Settings.Default.OverlayLastYPos);
            }
            else
            {
                this.Gover.Close();
                t.Text = "Open Game Overlay";
            }
        }

        private void removeCharacterToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem T = sender as ToolStripMenuItem;
            ListViewItem temp = T.Tag as ListViewItem;
            Character C = temp.Tag as Character;

            C.WatchChar = false;
            this.Lv_Stats.Items.Remove(temp);
        }

        private void discoverableModeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem T = sender as ToolStripMenuItem;

            if (!T.Checked)
            {
                List<Character> C = this.Chars.FindAll(
                    delegate(Character c)
                    {
                        return (c.WatchChar == false && c.isPet == false);
                    }
                );

                foreach (Character c in C)
                    this.Chars.Remove(c);
            }

            try
            {
                this.Gover.DiscoverableModeOn = T.Checked;
            }
            catch { }
        }

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SettingsForm SF = new SettingsForm();
            SF.ShowDialog();

            this.Gover.ResetSettings();
        }

        private void stopReadingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.timer.Enabled = false;
            this.StripLbl_Status.Text = "Paused";
        }

        public void resetReadingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.EncounterRecords.Clear();
            this.currentencounter = null;
            this.LB_Entries.Items.Clear();
            foreach (Character C in this.Chars)
                C.Encounters.Clear();
        }

        private void addPetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Character C = ((sender as ToolStripMenuItem).Tag as ListViewItem).Tag as Character;
            AddCharacterDialog D = new AddCharacterDialog(this.Chars);

            DialogResult R = D.ShowDialog();

            if (R == System.Windows.Forms.DialogResult.OK)
            {
                if (D.ReturnsCharacter)
                {
                    D.SelectedCharacter.isPet = true;
                    C.Pets.Add(D.SelectedCharacter);
                }
                else
                {
                    Character temp = new Character(D.SelectedCharacterString);
                    temp.isPet = true;
                    this.Chars.Add(temp);
                    C.Pets.Add(temp);
                }
            }
        }

        private void removePetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Character C = ((sender as ToolStripMenuItem).Tag as ListViewItem).Tag as Character;
            AddCharacterDialog D = new AddCharacterDialog(C.Pets);

            DialogResult R = D.ShowDialog();

            if (R == System.Windows.Forms.DialogResult.OK)
                C.Pets.Remove(D.SelectedCharacter);
        }

        private void Lv_Stats_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            this.Lv_Stats.ListViewItemSorter = new ListViewItemComparer(e.Column);
            this.Lv_Stats.Sort();
        }

        public void SetDiscoverableMode()
        {
            this.discoverableModeToolStripMenuItem.Checked = !this.discoverableModeToolStripMenuItem.Checked;
            this.discoverableModeToolStripMenuItem_Click(this.discoverableModeToolStripMenuItem, null);
        }

        public bool DiscoverableModeOn
        {
            get { return this.discoverableModeToolStripMenuItem.Checked; }
        }

        public bool ViewModeisCurrentEncounter
        {
            get { return this.currentEncounterToolStripMenuItem.Checked; }
            set { this.currentEncounterToolStripMenuItem.Checked = value; }
        }

        public bool ViewModeisSessionTotals
        {
            get { return this.sessionTotalsToolStripMenuItem.Checked; }
            set { this.sessionTotalsToolStripMenuItem.Checked = value; }
        }

        public void OverlayClosedByOverlay()
        {
            this.openGameOverlayToolStripMenuItem.Text = "Open Game Overlay";
        }

        private void autoaddCharactersToWatchlistToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (Character C in this.Chars)
                C.WatchChar = true;
            Properties.Settings.Default.AutoAdd = this.autoaddCharactersToWatchlistToolStripMenuItem.Checked;
            Properties.Settings.Default.Save();
        }

        public void NamecurrentEncounter(String name)
        {
            this.currentencounter.Name = name;
            foreach (Character C in this.Chars)
            {
                Encounter E = C.Encounters.Find(
                    delegate(Encounter e)
                    {
                        return e.EncounterID == this.currentencounter.EncounterID;
                    }
                );

                E.Name = name;
            }

            this.Stat_Lbl_Current_Encounter.Text = "Current Encounter: " + this.currentencounter.ToString();
        }

        private void NameCurrentEncounter(object sender, EventArgs e)
        {
            EncounterNamer EN = new EncounterNamer();

            DialogResult DR = EN.ShowDialog();

            if (DR == System.Windows.Forms.DialogResult.OK)
                this.NamecurrentEncounter(EN.NameEntered);
        }
    }
}
